package celcatSynchronizer.ui;

import celcatSynchronizer.CelcatSynchronizer;
import celcatSynchronizer.CsvExporter;
import celcatSynchronizer.DbComparator;
import celcatSynchronizer.DbCreator;
import celcatSynchronizer.GoogleInterface;
import celcatSynchronizer.Group;
import com.google.gdata.data.calendar.CalendarEntry;
import com.toedter.calendar.JDateChooser;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import util.Config;

/**
 * Frame principale de l'application.
 */
public class FrameMain extends JFrame implements ActionListener, ListSelectionListener
{
	// Couleurs.
	private final static Color s_colorTitledBorder = Color.blue.darker();
	private final static Color s_colorValidState = Color.green.darker();
	private final static Color s_colorInvalidState = Color.red.darker();
	
	// Menus de la fenêtre
	private final JMenuItem m_menuItemQuit;
	private final JMenuItem m_menuItemAbout;
	
	// Modèles.
	private final ComboModelGroup m_comboModelGroup;
	private final ListModelCalendar m_listModelCalendar;
	
	// Composants graphiques.
	private final JDateChooser m_dateChooserConfigStartWeek;
	private final JButton m_buttonConfigSave;
	private final JTextField m_textFieldCsvFileName;
	private final JButton m_buttonCsvFileBrowse;
	private final JTextField m_textFieldGoogleLogin;
	private final JPasswordField m_passwordFieldGooglePassword;
	private final JButton m_buttonGoogleConnect;
	private final JList m_listGoogleCalendars;
	private final JComboBox m_comboGroups;
	private final JLabel m_labelExportDb;
	private final JLabel m_labelExportGroup;
	private final JLabel m_labelExportCalendar;
	private final JButton m_buttonExport;
	
	// Variables d'exploitation.
	private Connection m_db;
	private GoogleInterface m_googleInterface;
	
	/**
	 * Constructeur.
	 */
	public FrameMain()
	{
		super("Celcat Synchronizer v" + CelcatSynchronizer.version.toString());
		
		// Mise en place de la barre de menu.
		JMenu menuFile = new JMenu("Fichier");
			m_menuItemQuit = new JMenuItem("Quitter");
			m_menuItemQuit.addActionListener(this);
		menuFile.add(m_menuItemQuit);
		
		JMenu menuHelp = new JMenu("?");
			m_menuItemAbout = new JMenuItem("A propos");
			m_menuItemAbout.addActionListener(this);
		menuHelp.add(m_menuItemAbout);
		
		JMenuBar menuBar = new JMenuBar();
		menuBar.add(menuFile);
		menuBar.add(menuHelp);
		
		setJMenuBar(menuBar);		

		GridBagConstraints c = new GridBagConstraints();
		c.fill = GridBagConstraints.BOTH;
		c.insets = new Insets(3, 3, 3, 3);

		// Panel de configuration.
		JPanel panelConfig = new JPanel(new GridBagLayout());
		TitledBorder panelConfigBorder = new TitledBorder("Configuration");
		panelConfigBorder.setTitleColor(s_colorTitledBorder);
		panelConfig.setBorder(panelConfigBorder);
		
		c.gridx = 0;
		c.gridy = 0;
		panelConfig.add(new JLabel("Semaine 1 :"), c);
		c.gridx = 1;
		m_dateChooserConfigStartWeek = new JDateChooser(new Date(Long.parseLong(CelcatSynchronizer.config.getProperty("startWeek"))));
		m_dateChooserConfigStartWeek.setPreferredSize(new Dimension(200, m_dateChooserConfigStartWeek.getSize().height));
		panelConfig.add(m_dateChooserConfigStartWeek, c);
		c.gridx = 2;
		m_buttonConfigSave = new JButton("Enregistrer");
		m_buttonConfigSave.addActionListener(this);
		panelConfig.add(m_buttonConfigSave, c);
		
		// Panel de sélection du fichier CSV.
		JPanel panelLoadCsv = new JPanel(new GridBagLayout());
		TitledBorder panelLoadCsvBorder = new TitledBorder("Sélection du fichier csv de la base Celcat");
		panelLoadCsvBorder.setTitleColor(s_colorTitledBorder);
		panelLoadCsv.setBorder(panelLoadCsvBorder);
		
		c.gridx = 0;
		c.gridy = 0;
		panelLoadCsv.add(new JLabel("Fichier :"), c);
		c.gridx = 1;
		m_textFieldCsvFileName = new JTextField(40);
		m_textFieldCsvFileName.setEditable(false);
		panelLoadCsv.add(m_textFieldCsvFileName, c);
		c.gridx = 2;
		m_buttonCsvFileBrowse = new JButton("Parcourir...");
		m_buttonCsvFileBrowse.addActionListener(this);
		panelLoadCsv.add(m_buttonCsvFileBrowse, c);
		c.gridwidth = 1;
		c.gridheight = 1;
		c.gridx = 0;
		c.gridy = 1;
		panelLoadCsv.add(new JLabel("Groupe :"), c);
		c.gridx = 1;
		c.gridwidth = 2;
		m_comboModelGroup = new ComboModelGroup();
		m_comboGroups = new JComboBox(m_comboModelGroup);
		m_comboGroups.setRenderer(new ListCellRendererGroup());
		m_comboGroups.addActionListener(this);
		panelLoadCsv.add(m_comboGroups, c);
		c.gridwidth = 1;

		// Panel de connexion au service Google Calendars.
		JPanel panelGoogleCalendars = new JPanel(new GridBagLayout());
		TitledBorder panelGoogleCalendarsBorder = new TitledBorder("Google Calendars");
		panelGoogleCalendarsBorder.setTitleColor(s_colorTitledBorder);
		panelGoogleCalendars.setBorder(panelGoogleCalendarsBorder);
		
		c.gridx = 0;
		c.gridy = 0;
		panelGoogleCalendars.add(new JLabel("Login :"), c);
		c.gridx = 1;
		m_textFieldGoogleLogin = new JTextField(CelcatSynchronizer.config.getProperty("lastLogin"), 20);
		panelGoogleCalendars.add(m_textFieldGoogleLogin, c);
		c.gridx = 0;
		c.gridy = 1;
		panelGoogleCalendars.add(new JLabel("Mot de passe :"), c);
		c.gridx = 1;
		m_passwordFieldGooglePassword = new JPasswordField(20);
		panelGoogleCalendars.add(m_passwordFieldGooglePassword, c);
		c.gridx = 0;
		c.gridy = 2;
		c.gridwidth = 2;
		m_buttonGoogleConnect = new JButton("Connexion");
		m_buttonGoogleConnect.addActionListener(this);
		panelGoogleCalendars.add(m_buttonGoogleConnect, c);
		c.gridx = 2;
		c.gridy = 0;
		c.gridwidth = 1;
		c.gridheight = 4;
		m_listModelCalendar = new ListModelCalendar();
		m_listGoogleCalendars = new JList(m_listModelCalendar);
		m_listGoogleCalendars.setCellRenderer(new ListCellRendererCalendar());
		m_listGoogleCalendars.addListSelectionListener(this);
		m_listGoogleCalendars.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		JScrollPane scrollPaneGoogleCalendars = new JScrollPane(m_listGoogleCalendars);
		scrollPaneGoogleCalendars.setPreferredSize(new Dimension(200, 150));
		panelGoogleCalendars.add(scrollPaneGoogleCalendars, c);
		c.gridheight = 1;
		c.ipadx = 0;
		c.ipady = 0;
		
		// Panel d'exportation du fichier CSV résultat.
		JPanel panelExport = new JPanel(new GridBagLayout());
		TitledBorder panelExportBorder = new TitledBorder("Exportation CSV");
		panelExportBorder.setTitleColor(s_colorTitledBorder);
		panelExport.setBorder(panelExportBorder);
		
		c.gridx = 0;
		c.gridy = 0;
		panelExport.add(new JLabel("Base de données Celcat :"), c);
		c.gridx = 1;
		m_labelExportDb = new JLabel();
		m_labelExportDb.setPreferredSize(new Dimension(300, m_labelExportDb.getSize().height));
		m_labelExportDb.setHorizontalAlignment(JLabel.CENTER);
		m_labelExportDb.setForeground(Color.white);
		m_labelExportDb.setOpaque(true);
		panelExport.add(m_labelExportDb, c);
		c.gridx = 0;
		c.gridy = 1;
		panelExport.add(new JLabel("Groupe sélectionné :"), c);
		c.gridx = 1;
		m_labelExportGroup = new JLabel();
		m_labelExportGroup.setPreferredSize(new Dimension(300, m_labelExportDb.getSize().height));
		m_labelExportGroup.setHorizontalAlignment(JLabel.CENTER);
		m_labelExportGroup.setForeground(Color.white);
		m_labelExportGroup.setOpaque(true);
		panelExport.add(m_labelExportGroup, c);
		c.gridx = 0;
		c.gridy = 2;
		panelExport.add(new JLabel("Calendrier sélectionné :"), c);
		c.gridx = 1;
		m_labelExportCalendar = new JLabel();
		m_labelExportCalendar.setPreferredSize(new Dimension(300, m_labelExportCalendar.getSize().height));
		m_labelExportCalendar.setHorizontalAlignment(JLabel.CENTER);
		m_labelExportCalendar.setForeground(Color.white);
		m_labelExportCalendar.setOpaque(true);
		panelExport.add(m_labelExportCalendar, c);
		c.gridx = 0;
		c.gridy = 3;
		c.gridwidth = 2;
		m_buttonExport = new JButton("Exporter");
		m_buttonExport.addActionListener(this);
		panelExport.add(m_buttonExport, c);
		
		// Panel principal.
		JPanel panelMain = (JPanel)getContentPane();
		panelMain.setLayout(new BoxLayout(panelMain, BoxLayout.Y_AXIS));
	    panelMain.add(panelConfig);
	    panelMain.add(panelLoadCsv);
	    panelMain.add(panelGoogleCalendars);
	    panelMain.add(panelExport);
		
		setUiExportState();
		pack();
		
		setResizable(false);
	}
	
	/**
	 * Méthode de mise à jour des champs dynamiques du panel d'exportation.
	 */
	private void setUiExportState()
	{
		// Bandeau de chargement de la base de données.
		boolean dbState = (m_db != null);
		m_comboGroups.setEnabled(dbState);
		if(dbState)
		{
			m_labelExportDb.setBackground(s_colorValidState);
			m_labelExportDb.setText("Chargée");
		}
		else
		{
			m_labelExportDb.setBackground(s_colorInvalidState);
			m_labelExportDb.setText("Non chargée");
		}
		
		// Bandeau de sélection d'un groupe.
		boolean groupState = (m_comboGroups.isEnabled());
		if(groupState)
		{
			m_labelExportGroup.setBackground(s_colorValidState);
			m_labelExportGroup.setText(((Group)m_comboGroups.getSelectedItem()).getName());
		}
		else
		{
			m_labelExportGroup.setBackground(s_colorInvalidState);
			m_labelExportGroup.setText("Aucun");
		}
		
		// Bandeau de sélection d'un calendrier.
		boolean googleCalendarState = (m_listGoogleCalendars.getSelectedIndex() != -1);
		if(googleCalendarState)
		{
			m_labelExportCalendar.setBackground(s_colorValidState);
			m_labelExportCalendar.setText(((CalendarEntry)m_listGoogleCalendars.getSelectedValue()).getTitle().getPlainText());
		}
		else
		{
			m_labelExportCalendar.setBackground(s_colorInvalidState);
			m_labelExportCalendar.setText("Aucun");
		}
		
		// On active le bouton export si les trois bandeaux sont OK.
		m_buttonExport.setEnabled(dbState && groupState && googleCalendarState);
	}
	
	@Override
	public void actionPerformed(ActionEvent p_event)
	{
		Object source = p_event.getSource();
		if(source == m_menuItemQuit)
			dispose();
		else if(source == m_menuItemAbout)
		{
			JOptionPane.showMessageDialog(
				this,
				"<html>" +
				"Utilitaire créé dans le cadre du projet de fin de seconde année<br>" +
				"d'apprentissage à Polytech Paris-Sud.<br><br>" +
				"<b>Equipe :</b><br>" +
				"<ul>" +
				"<li>Yoann Braban</li>" +
				"<li>Sébastien Corbeau</li>" +
				"<li>Benjamin Hamon</li>" +
				"<li>Sophie Huart</li>" +
				"<li>Alain Le</li>" +
				"<li>Cyril Le Potier</li>" +
				"<li>Clément Martin</li>" +
				"<li>Jérémy Moriaud</li>" +
				"<li>Emmanuel Neret</li>" +
				"<li>Rémi Praud</li>" +
				"</ul>" +
				"</html>",
				"A propos...",
				JOptionPane.INFORMATION_MESSAGE
			);
		}
		else if(source == m_buttonConfigSave)
		{
			try
			{
				// Sauvegarde de la semaine sélectionnée dans le fichier de configuration.
				CelcatSynchronizer.config.setProperty("startWeek", String.valueOf(m_dateChooserConfigStartWeek.getCalendar().getTimeInMillis()));
				Config.store(CelcatSynchronizer.configFileName, CelcatSynchronizer.config);
				
				JOptionPane.showMessageDialog(
					this,
					"La configuration a été sauvegardée.",
					"Sauvegarde effectuée",
					JOptionPane.INFORMATION_MESSAGE
				);
			}
			catch(Exception ex)
			{
				CelcatSynchronizer.log.error("An exception occured while saving configuration file");
				CelcatSynchronizer.log.debug(ex);
				
				JOptionPane.showMessageDialog(
					this,
					"Une erreur est survenue durant la sauvegarde du fichier de configuration.",
					"Erreur",
					JOptionPane.ERROR_MESSAGE
				);
			}
		}
		else if(source == m_buttonCsvFileBrowse)
		{
			// Recherche d'un fichier CSV et chargement de la base de données Celcat.
			JFileChooser fc = new JFileChooser();
			fc.setFileFilter(new FileNameExtensionFilter("Base de données Celcat", "csv"));
			fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
			fc.setMultiSelectionEnabled(false);
			if(fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION)
			{
				File selectedFile = fc.getSelectedFile();
				
				try
				{
					DbCreator dbCreator = new DbCreator();
					m_db = dbCreator.createDb();
					dbCreator.feedDb(m_db, selectedFile);
					
					m_textFieldCsvFileName.setText(selectedFile.getAbsolutePath());
					
					//Recuperation des groupes et affichage sur l'interface.
					PreparedStatement statGroups = m_db.prepareStatement("SELECT _group_id, _name FROM CT_GROUP ORDER BY _name;");
					ResultSet rsGroups = statGroups.executeQuery();

					m_comboModelGroup.removeAllElements();
					while(rsGroups.next())
						m_comboModelGroup.addElement(new Group(rsGroups.getInt("_group_id"), rsGroups.getString("_name")));
					
					setUiExportState();
					
					JOptionPane.showMessageDialog(
						this,
						"Le fichier de base de données Celcat a été correctement chargé.",
						"Chargement réussi",
						JOptionPane.INFORMATION_MESSAGE
					);
				}
				catch(Exception ex)
				{
					CelcatSynchronizer.log.error("An exception occured while loading [" + selectedFile + "] csv file");
					CelcatSynchronizer.log.debug(ex);
					
					if(m_db != null)
					{
						try
						{
							m_db.close();
						}
						catch(SQLException ex1)
						{
						}
						
						m_db = null;
					}
					
					m_comboModelGroup.removeAllElements();
					m_textFieldCsvFileName.setText("");
					setUiExportState();
					
					JOptionPane.showMessageDialog(
						this,
						"Une erreur est survenue durant le chargement du fichier de base de données Celcat.",
						"Erreur",
						JOptionPane.ERROR_MESSAGE
					);
				}
			}
		}
		else if(source == m_comboGroups)
			setUiExportState();
		else if(source == m_buttonGoogleConnect)
		{
			// Connexion au service Google Calendars et récupération des calendriers.
			String login = m_textFieldGoogleLogin.getText();
			String password = new String(m_passwordFieldGooglePassword.getPassword());
			if(login.isEmpty() || password.isEmpty())
			{
				JOptionPane.showMessageDialog(
					this,
					"Veuillez spécifier le login et le mot de passe associé à votre compte Google.",
					"Erreur",
					JOptionPane.ERROR_MESSAGE
				);
				return;
			}
			
			try
			{
				m_googleInterface = new GoogleInterface(login, password);
				m_listModelCalendar.setEntries(m_googleInterface.getCalendars());
				setUiExportState();
				
				try
				{
					CelcatSynchronizer.config.setProperty("lastLogin", login);
					Config.store(CelcatSynchronizer.configFileName, CelcatSynchronizer.config);
				}
				catch(Exception exc)
				{
					CelcatSynchronizer.log.notice("Failed to save configuration file");
				}
			}
			catch(Exception ex)
			{
				CelcatSynchronizer.log.error("An exception occured while loading google calendars");
				CelcatSynchronizer.log.debug(ex);
				
				m_listModelCalendar.setEntries(new ArrayList<CalendarEntry>());
				setUiExportState();
				
				JOptionPane.showMessageDialog(
					this,
					"<html>" +
					"Une erreur est survenue durant le chargement de vos calendriers.<br>" +
					"Veuillez vérifier les login et mot de passe saisis.<br>" +
					"Assurez vous aussi de bien être connecté à internet." +
					"</html>",
					"Erreur",
					JOptionPane.ERROR_MESSAGE
				);
			}
		}
		else if(source == m_buttonExport)
		{
			// Exportation du fichier CSV resultat.
			JFileChooser fc = new JFileChooser();
			fc.setFileFilter(new FileNameExtensionFilter("Base de données Celcat", "csv"));
			fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
			fc.setMultiSelectionEnabled(false);
			if(fc.showSaveDialog(this) == JFileChooser.APPROVE_OPTION)
			{
				File selectedFile = fc.getSelectedFile();
				int groupId = ((Group)m_comboGroups.getSelectedItem()).getId();
				
				try
				{
					// On effectue les comparaisons à partir de la base Celcat et des event de Google Calendars.
					DbComparator dbComparator = new DbComparator();
					dbComparator.compareToDb((CalendarEntry)m_listGoogleCalendars.getSelectedValue(), m_googleInterface, m_db, groupId);

					// On exporte les events du groupe sélectionné sous format CSV.
					CsvExporter csvExporter = new CsvExporter();
					csvExporter.exportDb(m_db, selectedFile, groupId);
					
					JOptionPane.showMessageDialog(
						this,
						"Le fichier CSV a été généré avec succès.",
						"Opération effectuée",
						JOptionPane.INFORMATION_MESSAGE
					);
				}
				catch(Exception ex)
				{
					CelcatSynchronizer.log.error("An error occured while generating CSV file");
					CelcatSynchronizer.log.debug(ex);
					
					JOptionPane.showMessageDialog(
						this,
						"Une erreur est survenue durant la générationdu fichier CSV.",
						"Erreur",
						JOptionPane.ERROR_MESSAGE
					);
				}
			}
		}
	}

	@Override
	public void valueChanged(ListSelectionEvent p_event)
	{
		if(p_event.getSource() == m_listGoogleCalendars)
			setUiExportState();
	}
}
